﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Globalization;

namespace SocketClientAsyncTester
{
    class MessageArrayController
    {
        string[] arrayOfMessagesToSend;
        string[][] jaggedArrayOfMessages;
        string[] arrayOfMessages;
        string[] arrayOfMessagesToSendForLongTest;
        Int32 numberOfConnections;
        internal long startTime;

        public MessageArrayController(ConfigFileHandler configHandler, SocketClient socketClient)
        {
            numberOfConnections = configHandler.totalNumberOfClientConnectionsToRun;
            CreateMessageArrays(configHandler);
            arrayOfMessagesToSend = new string[configHandler.numberOfSentMessagesPerConnection];
            if (Program.runLongTest == true)
            {
                arrayOfMessagesToSend = arrayOfMessagesToSendForLongTest;
            }
            PushMessageArraysToSaeaObjects(socketClient);
            DisplayMessageForLongTest(configHandler);
        }

        private void CreateMessageArrays(ConfigFileHandler configHandler)
        {
            //We start by building all the messages
            //that we will send, and putting them in a jagged
            //array. This is just something we'll do for testing.
            //We don't want the message building to be a bottleneck
            //in the testing of our network app.
            //The top level size of the jagged array is equal
            //to the number of clients that we'll connect to the
            //server from this machine. The second level size
            //is equal to the number of messages that we'll send
            //from the client.
            string messageToSend = "";
            string tempMessageToSend = "";
            StringBuilder theStringBuilder;

            Console.WriteLine();
            Console.WriteLine("Creating arrays of messages to send to server from each client.");
            Console.WriteLine();
            
            //If you are running a test that is so long that it cannot be held 
            //in memory, then you can just send the same array of messages over 
            //and over, instead of having a separate array for each connection.
            if (Program.runLongTest == true)
            {
                arrayOfMessagesToSendForLongTest = new string[configHandler.numberOfSentMessagesPerConnection];
                Console.WriteLine("runLongTest == true. So, the same array of messages will be sent over and over, to conserve memory.");
                string myTempMessageToSend;
                for (int i = 0; i < configHandler.numberOfSentMessagesPerConnection; i++)
                {
                    myTempMessageToSend = "M" + (i + 1).ToString() + "-C0000";
                    arrayOfMessagesToSendForLongTest[i] = myTempMessageToSend;
                }
                Console.WriteLine();
                Console.WriteLine("array of messages built");               
            }

            else
            {
                
                Int64 count = Convert.ToInt64(configHandler.numberOfSentMessagesPerConnection * configHandler.totalNumberOfClientConnectionsToRun);
                if (count > 1000000)
                {
                    Console.WriteLine("runLongTest == false. So, all messages are put in memory first.\r\nIf you have a lot of messages to send, you'll use a lot of memory.");
                    Console.WriteLine("If you are running a test that is so long that it cannot\r\nbe held in memory, make Program.runLongTest = true.");
                }

                jaggedArrayOfMessages = new string[configHandler.totalNumberOfClientConnectionsToRun][];

                for (Int32 counter = 0; counter < configHandler.totalNumberOfClientConnectionsToRun; counter++)
                {
                    arrayOfMessages = new string[configHandler.numberOfSentMessagesPerConnection];
                    for (Int32 i = 0; i < configHandler.numberOfSentMessagesPerConnection; i++)
                    {
                        theStringBuilder = new StringBuilder();
                        tempMessageToSend = "M" + (i + 1).ToString() + "-C" + (counter + 1);

                        //You can change messageType to 1, if you want to generate
                        //just a few messages for each client, and where each message
                        //will be different.
                        Int32 messageType = 0;
                        if (messageType == 0)
                        {
                            messageToSend = tempMessageToSend;
                        }
                        else
                        {
                            //Let's change the messages up by just appending the same message
                            //once for each loop. So, notice that this will make them longer
                            //and longer. So, you might want to do something else, if you need
                            //to test sending a lot of messages from one client.

                            for (int j = 0; j < i + 1; j++)
                            {
                                theStringBuilder.Append(tempMessageToSend);
                            }
                            messageToSend = theStringBuilder.ToString();
                        }
                        arrayOfMessages[i] = messageToSend;
                    }
                    jaggedArrayOfMessages[counter] = arrayOfMessages;
                }
                Console.WriteLine();
                Console.WriteLine("array of messages built");
                Console.WriteLine("First message of first client starts on the next line");
                Console.WriteLine(jaggedArrayOfMessages[0][0]);
                Console.WriteLine("Last message of last client starts on the next line");
                Console.WriteLine(jaggedArrayOfMessages[configHandler.totalNumberOfClientConnectionsToRun - 1][configHandler.numberOfSentMessagesPerConnection - 1]);
            }
            NumberFormatInfo numFormat = new CultureInfo(CultureInfo.CurrentCulture.ToString(), false).NumberFormat;
            numFormat.NumberDecimalDigits = 0;

            Console.WriteLine("Number of connections to be started in this test = " + configHandler.totalNumberOfClientConnectionsToRun.ToString("n", numFormat));
            Console.WriteLine("Number of messages per connection = " + configHandler.numberOfSentMessagesPerConnection.ToString("n", numFormat));

            long totalMessages = Convert.ToInt64(configHandler.numberOfSentMessagesPerConnection)  * Convert.ToInt64(configHandler.totalNumberOfClientConnectionsToRun);
            Console.WriteLine("Total messages to be sent in this test = " + totalMessages.ToString("n", numFormat));
            Console.WriteLine();
            Console.WriteLine("Test is running ...");
            Console.WriteLine();
        }

        private void PushMessageArraysToSaeaObjects(SocketClient socketClient)
        {
            TimeSpan theTimeSpan = new TimeSpan(Program.tickDelayBeforeNextConn);
            startTime = DateTime.Now.Ticks;
            //Now we'll pass the messages to the clients and create them.
            for (Int32 counter = 0; counter < numberOfConnections; counter++)
            {                
                if (Program.useDelayBetweenConnections == true)
                {
                    Thread.Sleep(theTimeSpan);
                }

                if (Program.runLongTest != true)
                {
                    //get the array of messages that this client will send
                    arrayOfMessagesToSend = jaggedArrayOfMessages[counter];
                }
                //pass the messages to the SocketClient to send
                socketClient.GetMessages(arrayOfMessagesToSend);
            }
        }

        private void DisplayMessageForLongTest(ConfigFileHandler configHandler)
        {
            //If there is a long test, you may wonder how far along the test has
            //progressed, or if the machine has stopped working, or something.
            //This little function just let's you display a message showing 
            //approximately what percentage of the test is complete.
                        
            //We do NOT need to display it if there are only a few messages for
            //each connection. The number used here is just arbitrary.
            if (configHandler.numberOfSentMessagesPerConnection > 100)
            {
                Console.WriteLine();
                Console.WriteLine("All clients have started.");
                Console.WriteLine();
            }
        }
    }
}
